package com.ruoyi.web.service;

import cn.hutool.core.date.DateUtil;
import com.github.binarywang.wxpay.bean.request.WxPayRefundV3Request;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderV3Request;
import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderV3Result;
import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.util.WxPayUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 微信支付服务类
 * 
 * @author ruoyi
 */
@Service
public class WxPayService {

    private static final Logger log = LoggerFactory.getLogger(WxPayService.class);

    @Autowired
    private WxPayUtil wxPayUtil;

    @Value("${wxpay.notify-domain}")
    private String notifyDomain;

    /**
     * 创建微信支付订单
     * 
     * @param openid 用户openid
     * @param total 支付金额（分）
     * @param description 商品描述
     * @param outTradeNo 商户订单号
     * @return 支付结果
     */
    public AjaxResult createOrder(String openid, Integer total, String description, String outTradeNo) {
        log.info("开始创建微信支付订单，订单号：{}，金额：{}分，用户openid：{}", outTradeNo, total, openid);
        
        // 参数验证
        if (StringUtils.isEmpty(openid)) {
            return AjaxResult.error("用户openid不能为空");
        }
        if (total == null || total <= 0) {
            return AjaxResult.error("支付金额必须大于0");
        }
        if (StringUtils.isEmpty(description)) {
            return AjaxResult.error("商品描述不能为空");
        }
        if (StringUtils.isEmpty(outTradeNo)) {
            return AjaxResult.error("商户订单号不能为空");
        }
        
        Map<String, Object> map = new HashMap<>();
        
        try {
             com.github.binarywang.wxpay.service.WxPayService payService = wxPayUtil.getWxPayService();
            
            // 构建请求参数
            WxPayUnifiedOrderV3Request request = new WxPayUnifiedOrderV3Request();
            
            // 设置支付人信息
            WxPayUnifiedOrderV3Request.Payer payer = new WxPayUnifiedOrderV3Request.Payer();
            payer.setOpenid(openid);
            request.setPayer(payer);
            
            // 设置金额信息
            WxPayUnifiedOrderV3Request.Amount amount = new WxPayUnifiedOrderV3Request.Amount();
            amount.setTotal(total);
            amount.setCurrency("CNY");
            request.setAmount(amount);
            
            // 设置订单信息
            request.setDescription(description);
            request.setOutTradeNo(outTradeNo);
            
            // 设置过期时间（5分钟后过期）
            Date nowDate = new Date();
            Date dateAfter = new Date(nowDate.getTime() + 300000);
            String format = DateUtil.format(dateAfter, "yyyy-MM-dd'T'HH:mm:ssXXX");
            request.setTimeExpire(format);
            
            // 设置回调地址
            request.setNotifyUrl(notifyDomain + "/wxpay/notify");
            
            // 创建订单 - 使用V3接口
            WxPayUnifiedOrderV3Result orderV3 = payService.createOrderV3(TradeTypeEnum.JSAPI, request);
            log.info("微信支付订单创建成功，订单号：{}，预支付交易会话ID：{}", outTradeNo, orderV3.getPrepayId());
            map.put("data", orderV3);
            
            return AjaxResult.success(map);
            
        } catch (Exception e) {
            log.error("微信支付订单创建失败！订单号：{}，原因：{}", outTradeNo, e.getMessage(), e);
            map.put("data", "支付失败，请稍后重试！");
            return AjaxResult.error("支付失败，请稍后重试！");
        }
    }

    /**
     * 微信支付退款
     * 
     * @param outTradeNo 商户订单号
     * @param outRefundNo 商户退款单号
     * @param refundAmount 退款金额（分）
     * @param totalAmount 原订单金额（分）
     * @param reason 退款原因
     * @return 退款结果
     */
    public AjaxResult refund(String outTradeNo, String outRefundNo, Integer refundAmount, Integer totalAmount, String reason) {
        log.info("开始微信支付退款，订单号：{}，退款单号：{}，退款金额：{}分", outTradeNo, outRefundNo, refundAmount);
        
        // 参数验证
        if (StringUtils.isEmpty(outTradeNo)) {
            return AjaxResult.error("商户订单号不能为空");
        }
        if (StringUtils.isEmpty(outRefundNo)) {
            return AjaxResult.error("商户退款单号不能为空");
        }
        if (refundAmount == null || refundAmount <= 0) {
            return AjaxResult.error("退款金额必须大于0");
        }
        if (totalAmount == null || totalAmount <= 0) {
            return AjaxResult.error("原订单金额必须大于0");
        }
        if (refundAmount > totalAmount) {
            return AjaxResult.error("退款金额不能大于原订单金额");
        }
        
        Map<String, Object> map = new HashMap<>();
        
        try {
            com.github.binarywang.wxpay.service.WxPayService wxPayService = wxPayUtil.getWxPayService();
            
            // 构建退款请求
            WxPayRefundV3Request request = new WxPayRefundV3Request();
            
            // 设置订单号
            request.setOutTradeNo(outTradeNo);
            // 设置退款单号
            request.setOutRefundNo(outRefundNo);
            
            // 设置金额信息
            WxPayRefundV3Request.Amount amount = new WxPayRefundV3Request.Amount();
            amount.setCurrency("CNY");
            amount.setRefund(refundAmount);
            amount.setTotal(totalAmount);
            request.setAmount(amount);
            
            // 设置退款原因
            request.setReason(reason);
            
            // 执行退款
            Object refundResult = wxPayService.refundV3(request);
            log.info("微信支付退款成功，订单号：{}，退款单号：{}", outTradeNo, outRefundNo);
            map.put("data", refundResult);
            
            return AjaxResult.success(map);
            
        } catch (WxPayException e) {
            log.error("微信支付退款失败！订单号：{}，退款单号：{}，原因：{}", outTradeNo, outRefundNo, e.getMessage(), e);
            map.put("data", "退款失败，请稍后重试！");
            return AjaxResult.error("退款失败，请稍后重试！");
        }
    }

    /**
     * 生成商户订单号
     * 格式：WX + 时间戳 + 4位随机数
     * 
     * @return 商户订单号
     */
    public String generateOutTradeNo() {
        String timestamp = String.valueOf(System.currentTimeMillis());
        String random = String.format("%04d", (int)(Math.random() * 10000));
        return "WX" + timestamp + random;
    }

    /**
     * 生成商户退款单号
     * 格式：RF + 时间戳 + 4位随机数
     * 
     * @return 商户退款单号
     */
    public String generateOutRefundNo() {
        String timestamp = String.valueOf(System.currentTimeMillis());
        String random = String.format("%04d", (int)(Math.random() * 10000));
        return "RF" + timestamp + random;
    }

    /**
     * 元转分
     * 
     * @param yuan 金额（元）
     * @return 金额（分）
     */
    public Integer yuanToFen(Double yuan) {
        if (yuan == null || yuan <= 0) {
            return 0;
        }
        return (int) Math.round(yuan * 100);
    }

    /**
     * 分转元
     * 
     * @param fen 金额（分）
     * @return 金额（元）
     */
    public Double fenToYuan(Integer fen) {
        if (fen == null || fen <= 0) {
            return 0.0;
        }
        return fen / 100.0;
    }
}
